home *** CD-ROM | disk | FTP | other *** search
/ ftp.cs.arizona.edu / ftp.cs.arizona.edu.tar / ftp.cs.arizona.edu / icon / newsgrp / group94a.txt / 000010_icon-group-sender _Tue Jan 11 18:48:06 1994.msg < prev    next >
Internet Message Format  |  1994-08-19  |  6KB

  1. Received: by cheltenham.cs.arizona.edu; Tue, 11 Jan 1994 12:52:10 MST
  2. From: sperber@provence.informatik.uni-tuebingen.de (Michael Sperber [Mr. Preprocessor])
  3. Message-Id: <9401111748.AA28891@provence.informatik.uni-tuebingen.de>
  4. To: icon-group@cs.arizona.edu
  5. Reply-To: sperber@informatik.uni-tuebingen.de
  6. Subject: Icon and PTYs
  7. Date: Tue, 11 Jan 94 18:48:06 +0100
  8. Status: R
  9. Errors-To: icon-group-errors@cs.arizona.edu
  10.  
  11. I posted about this a while ago, and back then I wrote a kludgy
  12. solution called flush.  I use it for controlling an interactive SML
  13. compiler from an Icon program.  The basic idea is that flush starts a
  14. process on a tty, and forces all output to be flushed at each newline.
  15. This means you can open(..,"p..") a file from Icon, redirect output to
  16. a temp file an poll that file for output to arrive.
  17.  
  18. Problem is this is the first (and only) pty code I ever wrote.  I've
  19. tried to conform to the BSD docs that I have, but I'm not sure it runs
  20. on anything but AIX.  I'd be grateful if someone else could give this
  21. a whirl and tell me what I need to change to make it run on other
  22. architectures.
  23.  
  24. If there's interest, I could post the compiler driver also as an
  25. example.
  26.  
  27. Since this project has shown me that Icon is - except for
  28. pipe/socket/pty handling - ideally suited for controlling interactive
  29. programs, I'd really appreciate Icon had an option to open that
  30. would start a process on a pty pipe.
  31.  
  32. Cheers =8-} Chipsy
  33.  
  34. --snip, snip--
  35. /* flush.c : execute the command on the command line
  36.              through a pty making sure all the output
  37.          from the command is flushed on a
  38.          line-by-line basis. */
  39.  
  40. /* $Log: flush.c,v $
  41.  * Revision 1.2  1993/07/20  13:41:30  sperber
  42.  * New version with pty code from rxvt.
  43.  * */
  44.  
  45. #include <stdio.h>
  46. #include <stdlib.h>
  47. #include <fcntl.h>
  48. #include <unistd.h>
  49. #include <errno.h>
  50. #include <termio.h>
  51. #include <sys/ioctl.h>
  52. #include <sys/types.h>
  53. #include <sys/wait.h>
  54.  
  55. static char rcsid[] = "$Id: flush.c,v 1.2 1993/07/20 13:41:30 sperber Exp sperber $";
  56.  
  57. int
  58. main(int argc, char *argv[])
  59. {
  60.   void pass_through(int, int);
  61.   static char ptynam[] = "/dev/ptyxx";
  62.   static char ttynam[] = "/dev/ttyxx";
  63.   struct termios ttmode;
  64.   int ptyfd, ttyfd;
  65.   int uid, gid;
  66.   unsigned char *s3, *s4;
  67.   int i;
  68.   int width, height;
  69.   static char ptyc3[] = "pqrstuvwxyz";
  70.   static char ptyc4[] = "0123456789abcdef";
  71.   unsigned char argv0[256];
  72.   int comm_pid;
  73.  
  74.   /*  First find a master pty that we can open.
  75.    */
  76.   ptyfd = -1;
  77.   for (s3 = ptyc3; *s3 != 0; s3++) 
  78.     {
  79.       for (s4 = ptyc4; *s4 != 0; s4++) 
  80.     {
  81.       ptynam[8] = ttynam[8] = *s3;
  82.       ptynam[9] = ttynam[9] = *s4;
  83.       if ((ptyfd = open(ptynam, O_RDWR)) >= 0) 
  84.         {
  85.           if (geteuid() == 0 || access(ttynam, R_OK|W_OK) == 0)
  86.         break;
  87.           else 
  88.         {
  89.           close(ptyfd);
  90.           ptyfd = -1;
  91.         }
  92.         }
  93.     }
  94.       if (ptyfd >= 0)
  95.     break;
  96.     }
  97.   if (ptyfd < 0) 
  98.     {
  99.       perror("Can't open a pseudo teletype");
  100.       return(-1);
  101.     }
  102.  
  103.   fcntl(ptyfd, F_SETFL, O_NDELAY);
  104.   
  105.   comm_pid = fork();
  106.   if (comm_pid < 0) 
  107.     {
  108.       perror("Can't fork");
  109.       return(-1);
  110.     }
  111.   if (comm_pid == 0) 
  112.     {
  113.       if (setsid() < 0)
  114.     perror("failed to set process group");
  115.       
  116.       if ((ttyfd = open(ttynam, O_RDWR)) < 0) 
  117.     {
  118.       perror("could not open slave tty");
  119.       exit(1);
  120.     }
  121.       uid = getuid();
  122.  
  123.       dup2(ttyfd, fileno(stdin));
  124.       dup2(ttyfd, fileno(stdout));
  125.       dup2(ttyfd, fileno(stderr));
  126.  
  127.       ttmode.c_iflag = BRKINT | IGNPAR | ISTRIP | ICRNL | IXON | IMAXBEL;
  128.       ttmode.c_oflag = OPOST | ONLCR;
  129.       ttmode.c_cflag = B9600 | PARENB | CS8 | CREAD;
  130.       ttmode.c_lflag = ISIG | IEXTEN | ICANON;
  131.       ttmode.c_cc[VINTR] = 003;
  132.       ttmode.c_cc[VQUIT] = 034;
  133.       ttmode.c_cc[VERASE] = 0177;
  134.       ttmode.c_cc[VKILL] = 025;
  135.       ttmode.c_cc[VEOF] = 004;
  136.       ttmode.c_cc[VEOL] = 000;
  137.       ttmode.c_cc[VEOL2] = 001;
  138.       ttmode.c_cc[VSTART] = 000;
  139.       ttmode.c_cc[VSTOP] = 021;
  140.       ttmode.c_cc[VSUSP] = 023;
  141.       ttmode.c_cc[VDSUSP] = 032;
  142.       ttmode.c_cc[VREPRINT] = 022;
  143.       ttmode.c_cc[VDISCRD] = 022;
  144.       ttmode.c_cc[VWERSE] = 017;
  145.       ttmode.c_cc[VLNEXT] = 027;
  146.     
  147.       ioctl(0,TCSETS,(char *)&ttmode);
  148.  
  149.       setgid(getgid());
  150.       setuid(uid);
  151.       execvp(argv[1], argv+1);
  152.       fprintf(stderr, "Couldn't execute %s",argv[1]);
  153.       exit(1);
  154.     }
  155.   pass_through(comm_pid, ptyfd);
  156.   exit(0);
  157. }
  158.  
  159. void
  160. pass_through(pid_t pid, int fd)
  161. {
  162.   char in_char = '\0', out_char;
  163.   int n, in_pending = 0, term = 0, stdin_alive = 1;
  164.   int fd_stdin = fileno(stdin);
  165.  
  166.   if (fcntl(fd_stdin, F_SETFL, fcntl(fd_stdin, F_GETFL, 0) | O_NONBLOCK) == -1)
  167.     {
  168.       perror("F_SETFL");
  169.       exit(1);
  170.     }
  171.  
  172.   for (;;)
  173.     {
  174.       if (in_pending)
  175.     {
  176.       n = write(fd, &in_char, 1);
  177.       if (n == 1)
  178.         in_pending = 0;
  179.     }
  180.  
  181.       if (stdin_alive && !in_pending) 
  182.     {
  183.       n = read(fd_stdin, &in_char, 1);
  184.       if (n == -1)
  185.         {
  186.           if (errno != EAGAIN)
  187.         {
  188.           perror("unknown error during unblocked read");
  189.           exit(1);
  190.         }
  191.         }
  192.       else if (n == 1)
  193.         in_pending = 1;
  194.       else if (!n) /* EOF on stdin */
  195.         {
  196.           in_char = '\004';
  197.           in_pending = 1;
  198.           stdin_alive = 0; 
  199.         }
  200.     }
  201.  
  202.       term = waitpid(pid, 0, WNOHANG);
  203.       n = read(fd, &out_char, 1);
  204.       if (n < 1 && term)
  205.     {
  206.       fflush(stdout);
  207.       close(fd);
  208.       exit(0);
  209.     }
  210.       if (n == 1)
  211.     {
  212.       putchar(out_char);
  213.        if (out_char == '\n')
  214.         fflush(stdout);
  215.     }
  216.     }
  217. }
  218.  
  219.  
  220.  
  221.  
  222.